package com.liuguang.gateway.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.liuguang.common.pojo.CommonResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName: TestController
 * @Description：
 * @Author: wanghr
 * Date: 3:20 PM 2020/10/14
 * Version: 1.0
 */
@RestController
@RequestMapping("/test/")
public class TestController {
    private static final Logger logger = LoggerFactory.getLogger(TestController.class);

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @RequestMapping("rabbitmq")
    public CommonResult testRabbitmq() {
        logger.info("开始测试：-----------------");
        HashMap<String, String> map = new HashMap<>();
        map.put("afsgdh", "111111111111");
        rabbitTemplate.convertAndSend("DIRECT_EXCHANGE", "EMAIL_ROUTING_KEY", map);
        return CommonResult.success();
    }

    @RequestMapping("/sentinel2")
    public CommonResult testSentinel2() {
        logger.info("开始测试 sentinel 熔断降级");
        logger.info("模拟异常，测试异常数模式");
        //todo:controllerAdvice 会对异常进行友好返回，但是会影响sentinel 异常统计吗？
        int a = 1 / 0;
        return CommonResult.success();
    }

    @RequestMapping("/sentinel1")
    public CommonResult testSentinel1() {
        logger.info("开始测试 sentinel 网关中限流控制");

        logger.info("通过线程睡眠的模式，模拟线程占用");
        try {
            TimeUnit.MINUTES.sleep(45);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return CommonResult.success();
    }

    //在类内定义限流异常处理方法
//    @SentinelResource(value = "mySource1", blockHandler = "handleBlock", fallback = "handleException")
    //在类外定义限流异常处理方法
    @SentinelResource(value = "mySource1",blockHandlerClass = {com.liuguang.gateway.config.sentinel.MySentinelExceptionHandler.class},
            blockHandler = "handleBlockException",
            fallbackClass = {com.liuguang.gateway.config.sentinel.MySentinelExceptionHandler.class},
            fallback = "handleException")
    @RequestMapping("/sentinel")
    public CommonResult testSentinel() {
        logger.info("开始测试 sentinel 服务中方法限流");
        // ==============
        logger.info("模拟出现异常");
//        这个异常在哪里捕获？controllerAdvice 还是 在设置的异常处理方法中？
        int a = 1 / 0;

        //==========
        logger.info("通过线程睡眠的模式，模拟线程占用");
        try {
            TimeUnit.SECONDS.sleep(15);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return CommonResult.success();
    }

    //放到配置类中
//    @PostConstruct
    public void initFlowRules() {
        logger.info("初始化资源数据=========");
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("mySource1");
        // 0：线程数；1：qps，
        rule.setGrade(0);
        // Set limit QPS to 20.
        rule.setCount(1);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }

    /**
     * sentinel 处理限流方法
     */
    public CommonResult handleBlock(BlockException e) {
        logger.info("进入限流处理方法");
        e.printStackTrace();
        String message = e.getMessage();
        System.out.println("message = " + message);
        return CommonResult.success(message);
    }

    /**
     * sentinel 处理异常方法
     */
    public CommonResult handleException(Throwable throwable) {
        logger.info("进入 sentinel 处理异常方法");
        System.out.println(throwable.getMessage());
        return CommonResult.success(throwable.getMessage());
    }
}
